package com.aysafety.eventmodel.service.geosound.impl;

import com.aysafety.eventmodel.common.DateUtils;
import com.aysafety.eventmodel.common.PythonAlgorithmUtils;
import com.aysafety.eventmodel.dao.GeoSoundDao;
import com.aysafety.eventmodel.dao.MicroseismDao;
import com.aysafety.eventmodel.dao.TreeDao;
import com.aysafety.eventmodel.service.geosound.GeosoundService;
import com.safety.algorithm.eigenvalue.EigenvalueAlgorithm;
import com.safety.algorithm.eigenvalue.geosound.GeosoundAlgorithm;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.*;

/**
 * @program: iotDataPlatform
 * @description: 地音
 * @author: ChengQi
 * @create: 2019-02-18 11:49
 **/
@Service public class GeosoundImpl implements GeosoundService {

    @Autowired TreeDao treeDao;

    @Autowired GeoSoundDao geoSoundDao;
    @Autowired PythonAlgorithmUtils pythonAlgorithmUtils;

    @Autowired
    MicroseismDao microseismDao;
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    // 删除ArrayList中重复元素，保持顺序
    private static List<Map<String, Object>> removeDuplicateWithOrder(List<Map<String, Object>> list) {
        Set<Map<String, Object>> set = new HashSet<Map<String, Object>>();
        List<Map<String, Object>> newList = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < list.size(); i++) {
            Map<String, Object> map = new HashMap<String, Object>(2);
            map.put("entId", list.get(i).get("entId"));
            map.put("deviceId", list.get(i).get("deviceId"));
            if (set.add(map)) {
                newList.add(map);
            }
        }
        return newList;
    }

    /**
     * @Description: 能量平均值、能量偏差值
     * @Param: [currentTime]
     * @return: void
     * @Author: ChengQi
     * @Date: 2019/2/18
     */
    @Override public void calAvg(String currentTime) throws Exception {
        //[t-1,t]
        String startTime =
            DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", DateUtils.getBeforeMinuteDate(-60, currentTime));
        String endTime = DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", currentTime);

        Map<String, Object> treeMap = new HashMap<String, Object>(1);
        treeMap.put("type", "\'" + "Geosound" + "\'");
        // 树
        List<Map<String, Object>> tree = removeDuplicateWithOrder(treeDao.queryTreeData(treeMap));
        for (Map<String, Object> treeData : tree) {
            String entId = treeData.get("entId").toString();
            String deviceId = treeData.get("deviceId").toString();
            Map<String, Object> parram = new HashMap<String, Object>();
            parram.put("tableId", entId + "." + "GEOSOUNDREALTIME");
            parram.put("deviceId", "\'" + deviceId + "\'");
            parram.put("startTime", DateUtils.fomatDateTime(startTime).getTime());
            parram.put("endTime", DateUtils.fomatDateTime(endTime).getTime());
            //查询1分钟内所有数据
            List<Map<String, Object>> datas = geoSoundDao.queryRealTimeByGeoSound(parram);

            for (int i = 0; i < datas.size(); i++) {
                Map<String, Object> map = datas.get(i);

                String datetime = DateUtils.getTime(DateUtils.fomatDateTime((Long) map.get("datetime")));
                if (StringUtils.isBlank(datetime)) {
                    continue;
                }
                double emergoa = -1;
                if (map.containsKey("emergoa") && null != map.get("emergoa")) {
                    emergoa = Double.parseDouble(map.get("emergoa").toString());
                }

                long eTime = (long) map.get("datetime");
                long sTime = eTime - 6 * 60 * 60 * 1000;
                parram.put("startTime", sTime);
                parram.put("endTime", eTime);
                //向前查询6小时的数据
                List<Map<String, Object>> subDatas = geoSoundDao.queryRealTimeByGeoSound(parram);
                //能量平均值
                double avg = GeosoundAlgorithm.average(subDatas);
                /**************计算能量偏差值****************/
                sTime = eTime - 24 * 60 * 60 * 1000;
                parram.put("startTime", sTime);
                List<Map<String, Object>> hourList24 = geoSoundDao.queryRealTimeByGeoSound(parram);
                double avg24 = GeosoundAlgorithm.average(hourList24);
                double energyDeviation = EigenvalueAlgorithm.divide(emergoa - avg24, avg24, 0);
                Map<String, Object> resultMap = new HashMap<String, Object>();
                resultMap.put("pk", "\'" + eTime + ".:." + deviceId + "\'");
                resultMap.put("entId", "\'" + entId + "\'");
                resultMap.put("deviceId", "\'" + deviceId + "\'");
                resultMap.put("datetime", eTime);
                resultMap.put("avgEmergoa", avg);
                resultMap.put("energyDeviation", energyDeviation);
                resultMap.put("tableId", entId + "." + "CalGeoEmergoa");
                System.out.println("avgEmergoa: " + resultMap);
                geoSoundDao.saveCal(resultMap);
            }
        }
    }

    /**
     * @Description: 脉冲、脉冲因子、脉冲偏差值
     * @Param: [currentTime]
     * @return: void
     * @Author: ChengQi
     * @Date: 2019/2/19
     */
    @Override public void calpulse(String currentTime) throws Exception {
        //[t-10,t]
        String startTime =
            DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", DateUtils.getBeforeMinuteDate(-600, currentTime));
        String endTime = DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", currentTime);

        Map<String, Object> treeMap = new HashMap<String, Object>(1);
        treeMap.put("type", "\'" + "Geosound" + "\'");
        // 树
        List<Map<String, Object>> tree = removeDuplicateWithOrder(treeDao.queryTreeData(treeMap));
        for (Map<String, Object> treeData : tree) {
            String entId = treeData.get("entId").toString();
            String deviceId = treeData.get("deviceId").toString();
            Map<String, Object> parram = new HashMap<String, Object>();
            parram.put("tableId", entId + "." + "GEOSOUNDREALTIME");
            parram.put("deviceId", "\'" + deviceId + "\'");
            parram.put("startTime", DateUtils.fomatDateTime(startTime).getTime());
            parram.put("endTime", DateUtils.fomatDateTime(endTime).getTime());

            //查询1分钟里所有数据
            List<Map<String, Object>> datas = geoSoundDao.queryRealTimeByGeoSound(parram);

            for (int i = 0; i < datas.size(); i++) {
                Map<String, Object> map = datas.get(i);
                long eTime = (long) map.get("datetime");
                long sTime = eTime - 10 * 60 * 1000;
                parram.put("startTime", sTime);
                parram.put("endTime", eTime);
                //查询单位时间记录数
                parram.put("tableId", entId + "." + "GEOSOUNDREALTIME");
                List<Map<String, Object>> realList = geoSoundDao.queryRealTimeByGeoSound(parram);
                //脉冲
                // long pulse = datas.size();
                long pulse = 0l;

                for (int j=0; j<datas.size(); j++) {
                    if ((double) datas.get(j).get("emergoa") > 0.0) {
                        pulse++;
                    }
                }

                sTime = eTime - 6 * 60 * 60 * 1000;
                parram.put("startTime", sTime);
                //6小时内数据
                List<Double> realListSix = geoSoundDao.queryRealTimeByEmergoaDesc(parram);
                double pulseFactor = 0.0;
                if (realListSix.size() > 24) {
                    double divisor = 10 * EigenvalueAlgorithm.average(realListSix.subList(0, 24));
                    double dividend = EigenvalueAlgorithm.average(realListSix);
                    //脉冲因子
                    pulseFactor = EigenvalueAlgorithm.divide(divisor, dividend, 0);
                } else {
                    pulseFactor = 0;
                }

                sTime = eTime - 24 * 60 * 60 * 1000;
                parram.put("startTime", sTime);
                parram.put("tableId", entId + "." + "CalGeoPulse");
                List<Map<String, Object>> hourList = geoSoundDao.queryCalPulse(parram);
                //脉冲偏差值
                double pulseDeviation = 0.0;
                if (hourList.size() > 0) {
                    double divisor24 = Double.parseDouble(hourList.get(0).get("pulse").toString()) - EigenvalueAlgorithm
                        .average(hourList, "pulse");
                    double dividend24 = EigenvalueAlgorithm.average(hourList, "pulse");
                    pulseDeviation = EigenvalueAlgorithm.divide(divisor24, dividend24, 0);
                }
                Map<String, Object> resultMap = new HashMap<String, Object>();
                resultMap.put("pk", "\'" + eTime + ".:." + deviceId + "\'");
                resultMap.put("entId", "\'" + entId + "\'");
                resultMap.put("deviceId", "\'" + deviceId + "\'");
                resultMap.put("datetime", eTime);
                resultMap.put("pulse", pulse);
                resultMap.put("pulseFactor", pulseFactor);
                resultMap.put("pulseDeviation", pulseDeviation);
                resultMap.put("tableId", entId + "." + "CalGeoPulse");
                System.out.println("pluse: " + resultMap);
                geoSoundDao.saveCal(resultMap);
            }
        }
    }



    /**
     * @Description: 每日能量偏差高值总数Ds、每日能量偏差高值总数Ds、日总、日均、日最高
     * @Param: []
     * @return: void
     * @Author: ChengQi
     * @Date: 2019/2/19
     */
    @Override public void daily(String currentTime) throws Exception {
        //前一天
        currentTime = DateUtils.getBeforeDayDate(-1, currentTime, "yyyy-MM-dd HH:mm:ss");
        String startTime = DateUtils.getCurrentStartTime("yyyy-MM-dd HH:mm:ss", currentTime);
        String endTime = DateUtils.getCurrentEndTime("yyyy-MM-dd HH:mm:ss", currentTime);
        //树
        Map<String, Object> treeMap = new HashMap<String, Object>(1);
        treeMap.put("type", "\'" + "Geosound" + "\'");
        List<Map<String, Object>> tree = removeDuplicateWithOrder(treeDao.queryTreeData(treeMap));
        for (Map<String, Object> map : tree) {

            String entId = map.get("entId").toString();
            String deviceId = map.get("deviceId").toString();
            Map<String, Object> parram = new HashMap<String, Object>();
            parram.put("tableId", entId + "." + "CalGeoEmergoa");
            parram.put("deviceId", "\'" + deviceId + "\'");
            parram.put("startTime", DateUtils.fomatDateTime(startTime).getTime());
            parram.put("endTime", DateUtils.fomatDateTime(endTime).getTime());
            //每日能量偏差高值总数Ds
            parram.put("energyDeviation", 2);
            long dailyEnergyDeviation = geoSoundDao.countHighDeviation(parram);
            parram.put("pulseDeviation", 2);
            parram.remove("energyDeviation");
            parram.put("tableId", entId + "." + "CalGeoPulse");
            long dailyPulseDeviation = geoSoundDao.countHighDeviation(parram);
            //日总、日均、日最高
            parram.put("tableId", entId + "." + "GEOSOUNDREALTIME");
            List<Map<String, Object>> realList = geoSoundDao.queryRealTimeByGeoSound(parram);
            Map<String, Object> result = EigenvalueAlgorithm.microseismEveryday(realList, startTime.substring(0, 10));
            double totalEnergy = Double.parseDouble(result.get("sum").toString());
            double maxEnergy = Double.parseDouble(result.get("max").toString());
            double avgEnergy = Double.parseDouble(result.get("average").toString());
            Map<String, Object> resultMap = new HashMap<String, Object>();
            resultMap.put("pk", "\'" + DateUtils.fomatDateTime(startTime).getTime() + deviceId + "\'");
            resultMap.put("entId", "\'" + entId + "\'");
            resultMap.put("deviceId", "\'" + deviceId + "\'");
            resultMap.put("datetime", DateUtils.fomatDateTime(startTime).getTime());
            resultMap.put("avgEmergoa", avgEnergy);
            resultMap.put("dailyEnergyDeviation", dailyEnergyDeviation);
            resultMap.put("dailyPulseDeviation", dailyPulseDeviation);
            resultMap.put("totalEnergy", totalEnergy);
            resultMap.put("maxEnergy", maxEnergy);
            resultMap.put("tableId", entId + "." + "CalDailyGeoSound");
            geoSoundDao.saveCal(resultMap);
        }
    }

    /**
     * @Description: 地音综合预警
     * @Param: [currentTime]
     * @return: void
     * @Author: ChengQi
     * @Date: 2019/2/28
     */
    /*@Override public void dailyComprehensiveWarning(String currentTime) throws Throwable {
        logger.info("正在计算地音综合预警，currentTime：" + currentTime);
        *//**
         * 1.获取实时数据数据
         * 	    能量：实时能量
         * 2.数据筛选
         * 	    kmeans聚类
         * 3.排序
         * 	    8小时时间段
         * 4.计算特征值
         *      能量：地音能量
         * 	    时间：地音能量均值
         * 	    空间：能量脉冲因子
         * 5.综合预警
         * *//*

        //当前时间
        currentTime = DateUtils.getHoursStartTime("yyyy-MM-dd HH:mm:ss", currentTime);
        //开始时间
        String startTime = DateUtils.getBeforehourDate(-8, currentTime);
        //结束时间
        String endTime = currentTime;
        //树
        Map<String, Object> treeMap = new HashMap<String, Object>(1);
        treeMap.put("type", "\'" + "Geosound" + "\'");
        List<Map<String, Object>> tree = removeDuplicateWithOrder(treeDao.queryTreeData(treeMap));
        for (int j = 0; j < tree.size(); j++) {
            Map<String, Object> map = tree.get(j);
            //矿id
            String entId = map.get("entId").toString();
            //工作面
            String deviceId = map.get("deviceId").toString();
            Map<String, Object> parram = new HashMap<String, Object>();
            parram.put("tableId", entId + "." + "GEOSOUNDREALTIME");
            parram.put("deviceId", "\'" + deviceId + "\'");
            parram.put("startTime", DateUtils.fomatDateTime(startTime).getTime());
            parram.put("endTime", DateUtils.fomatDateTime(endTime).getTime());
            List<Map<String, Object>> realList = geoSoundDao.queryRealTimeByGeoSound(parram);
            //判断是否存在大能量事件
            boolean largeFlag = false;
            List<Integer> largeList = new LinkedList<Integer>();
            List<Double> emergoaList = new LinkedList<Double>();
            if (realList.size() > 0) {
                for (int i = 0; i < realList.size(); i++) {
                    emergoaList.add(Double.parseDouble(realList.get(i).get("emergoa").toString()));
                    //System.out.println("emergoa=" + Double.parseDouble(realList.get(i).get("emergoa").toString()));
                    if (Double.parseDouble(realList.get(i).get("emergoa").toString()) > 100000) {
                        largeList.add(i);
                        largeFlag = true;
                    }
                }
            }

            if (!largeFlag) {
                //保存W,R
                Map<String, Object> resultMap = new HashMap<String, Object>();

                resultMap.put("pk", "\'" + DateUtils.fomatDateTime(startTime).getTime() + deviceId + "\'");
                resultMap.put("tableId", entId + "." + "CalWarningGeoSound");
                resultMap.put("entId", "\'" + entId + "\'");
                resultMap.put("deviceId", "\'" + deviceId + "\'");
                resultMap.put("datetime", DateUtils.fomatDateTime(currentTime).getTime());
                resultMap.put("w1", 0);
                resultMap.put("fitness", 0);
                resultMap.put("lastTime", 0);

                boolean flag = geoSoundDao.saveWarning(resultMap);
                logger.info("计算地音综合预警结束，无大能量。currentTime:" + currentTime);
                continue;
            }

            //2.数据筛选,地音不存在x,y,z跳过
            //4.计算特征值
            // 地音能量均值、地音能量均值
            List<Double> cList1 = new LinkedList<Double>();
            List<Double> cList2 = new LinkedList<Double>();
            for (int i = 0; i < realList.size(); i++) {
                long dateTime = (long) realList.get(i).get("datetime");
                Map<String, Object> calMap = calWarnCal(dateTime, entId, deviceId);
                cList1.add(Double.parseDouble(calMap.get("avg").toString()));
                cList2.add(Double.parseDouble(calMap.get("pulseFactor").toString()));
            }
            //5.综合预警
            Map<String, Object> reqMap = new HashMap<String, Object>();
            reqMap.put("nengliang", emergoaList);
            reqMap.put("pingci", cList1);
            reqMap.put("lisan", cList2);
            reqMap.put("shigu", largeList);
            reqMap.put("choose", "nengliang,pingci,lisan");
            System.out.println("正在进行遗传算法计算...");
            Map<String, Object> rep = pythonAlgorithmUtils.serviceGenetic(reqMap);
            System.out.println("遗传算法计算完成...rep: " + rep);
            int w1 = 0;
            String bestStr[] =
                rep.get("best").toString().substring(1, rep.get("best").toString().length() - 1).split(",");
            String fitness = rep.get("fitness").toString();
            for (int i = 0; i < emergoaList.size(); i++) {
                if (emergoaList.get(i) > Double.parseDouble(bestStr[0])) {
                    w1 += 1;
                }
            }

            for (int i = 0; i < cList1.size(); i++) {
                if (cList1.get(i) > Double.parseDouble(bestStr[1])) {
                    w1 += 1;
                }
            }

            for (int i = 0; i < cList2.size(); i++) {
                if (cList2.get(i) > Double.parseDouble(bestStr[2])) {
                    w1 += 1;
                }
            }

            //保存W,R
            Map<String, Object> resultMap = new HashMap<String, Object>();
            resultMap.put("pk", "\'" + DateUtils.fomatDateTime(startTime).getTime() + deviceId + "\'");
            resultMap.put("entId", "\'" + entId + "\'");
            resultMap.put("deviceId", "\'" + deviceId + "\'");
            resultMap.put("tableId", entId + "." + "CalWarningGeoSound");
            resultMap.put("datetime", DateUtils.fomatDateTime(currentTime).getTime());
            resultMap.put("w1", w1);
            System.out.println("w1: " + w1);
            resultMap.put("fitness", fitness);
            resultMap.put("lastTime", bestStr[3]);

            boolean flag = geoSoundDao.saveWarning(resultMap);
            logger.info("计算地音综合预警结束currentTime：" + currentTime + "，resultMap：" + resultMap);

        }
    }*/

    /**
    * @Description: 综合预警
    * @Param: [currentTime]
    * @return: void
    * @Author: ChengQi
    * @Date: 2019/4/3
    */
    @Override public void warning(String currentTime) throws Exception {
        //[t-1min,t]
        String startTime =
                DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", DateUtils.getBeforeMinuteDate(-60, currentTime));
        String endTime = DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", currentTime);

        Map<String, Object> treeMap = new HashMap<String, Object>(1);
        treeMap.put("type", "\'" + "Geosound" + "\'");

        //long etime = 0l;
        // 树
        List<Map<String, Object>> tree = removeDuplicateWithOrder(treeDao.queryTreeData(treeMap));
        for (Map<String, Object> treeData : tree) {
            String entId = treeData.get("entId").toString();
            String deviceId = treeData.get("deviceId").toString();
            long sTime = DateUtils.fomatDateTime(startTime).getTime();
            long eTime = DateUtils.fomatDateTime(endTime).getTime();

            Map<String, Object> parram = new HashMap<String, Object>();
            parram.put("tableId", entId + "." + "MICROSEISMREALTIME");
            parram.put("startTime", "\'" + sTime + "\'");
            parram.put("endTime", "\'" + eTime + "\'");
            List<Map<String, Object>> datas = microseismDao.queryRealMicroseism(parram);

            if (0 == datas.size()) {
                continue;
            }

            boolean bool = false;
            long etime = 0l;
            int maxw = 0;
            //double maxw2 = 0;
            double sumR = 0.0;
            Map<String, Double> rw = new HashMap<>();
            Map<String, Map<Double, Double>> warnResult = new HashMap<>();
            //查询学习出来的临界值
            parram.put("tableId", "GEOSOUNDWARNINGSTUDY");
            //parram.put("pk", "\'" + entId + "\'");
            parram.put("deviceId", "\'" + deviceId + "\'");
            List<Map<String, Object>> studyInfos = geoSoundDao.queryGeosoundWarningStudy(parram);
            for (Map<String, Object> studyInfo : studyInfos) {
                double best1 = Double.parseDouble(studyInfo.get("best1").toString());
                double best2 = Double.parseDouble(studyInfo.get("best2").toString());
                double best3 = Double.parseDouble(studyInfo.get("best3").toString());
                double R1 = Double.parseDouble(studyInfo.get("R1").toString());
                //String deviceId = (String) studyInfo.get("deviceId");
                sumR = sumR + R1;

                for (int i = 0; i < datas.size(); i++) {
                    //查询前8小时数据，判断maxW
                    double emergoa = Double.parseDouble(datas.get(i).get("emergoa").toString());
                    etime = (long) datas.get(i).get("datetime");
                    long stime = etime;
                    parram.put("endTime", etime);
                    parram.put("startTime", stime);
                    int w3 = 0;

                    // 能量均值
                    parram.put("tableId", entId + "." + "CALGEOEMERGOA");
                    List<Double> cList3 = geoSoundDao.queryGeosoundAvlEmergoa(parram);
                    // 脉冲因子
                    parram.put("tableId", entId + "." + "CALGEOPULSE");
                    List<Double> cList4 = geoSoundDao.queryGeosoundPulseFactor(parram);
                    if (cList3.size() != 1 || cList4.size() != 1) {
                        //实时能量未计算
                        bool = true;
                        continue;
                    } else {
                        if (emergoa > best1) {
                            w3++;
                        }
                        if (cList3.get(0) > best2) {
                            w3++;
                        }
                        if (cList4.get(0) > best3) {
                            w3++;
                        }
                        //rw.put(R1, (double) w3);
                        //rw.put(deviceId+"_" +R1, (double) w3);
                    }

                    etime = (long) datas.get(i).get("datetime");
                    stime = etime - 8 * 60 * 60 * 1000;
                    parram.put("endTime", "\'" + etime + "\'");
                    parram.put("startTime", "\'" + stime + "\'");
                    // 实时能量
                    parram.put("tableId", entId + "." + "MICROSEISMREALTIME");
                    List<Map<String, Object>> realList = microseismDao.queryRealMicroseism(parram);
                    List<Double> eList = new LinkedList<Double>();
                    for (int j = 0; j < realList.size(); j++) {
                        eList.add(Double.parseDouble(realList.get(j).get("emergoa").toString()));
                    }

                    parram.put("endTime", etime);
                    parram.put("startTime", stime);
                    // 能量均值
                    parram.put("tableId", entId + "." + "CALGEOEMERGOA");
                    parram.put("flag",1);
                    List<Double> cList1 = geoSoundDao.queryGeosoundAvlEmergoa(parram);
                    // 脉冲因子
                    parram.put("tableId", entId + "." + "CALGEOPULSE");
                    List<Double> cList2 = geoSoundDao.queryGeosoundPulseFactor(parram);
                    parram.remove("flag");
                    int w1 = 0;

                    for (int j = 0; j < eList.size(); j++) {
                        if (eList.get(j) > best1) {
                            w1++;
                        }
                        if (cList1.get(0) > best2) {
                            w1++;
                        }
                        if (cList2.get(0) > best3) {
                            w1++;
                        }

                        maxw = maxw > w1 ? maxw : w1;
                        rw.put(deviceId+"_" +R1, (double) w1);
                        //w1 = 0;
                    }

                    //计算W综
                    //double wz = computeWZ(maxw, sumR, rw);
                    //maxw2 = maxw2 > wz ? maxw2 : wz;
                    //Map<Double, Double> temp = new HashMap<>();
                    //temp.put(R1, (double) w1);
                    //warnResult.put(deviceId, temp);
                }
            }


            if (!bool) {
                double wResult = computeWZ(maxw, sumR, rw);
                System.out.println("wz:  " + wResult);
                Map<String, Object> resultMap = new HashMap<String, Object>();
                resultMap.put("tableId", entId + "." + "GEOSOUNDWARNING");
                resultMap.put("entId", "\'" + entId + "\'");
                resultMap.put("pk", "\'" + etime + "\'");
                resultMap.put("datetime", etime);
                resultMap.put("w", wResult);
                geoSoundDao.saveWarning(resultMap);
                bool = false;
            }


        }
    }


    /**
     * 计算地音多参量综合预警的W值
     * @param maxw
     * @param sumR
     * @param wr
     * @return
     */
    private double computeWZ(double maxw, double sumR, Map<String, Double> wr) {
        double result = 0.0;
        BigDecimal bigMaxW = new BigDecimal(maxw);
        BigDecimal bigSumR = new BigDecimal(sumR);
        for (Map.Entry<String, Double> entry : wr.entrySet()) {
            if (maxw == 0.0) {
                result = 0.0;
            } else {
                Double w = entry.getValue();
                BigDecimal bigW = new BigDecimal(w);
                String rString = entry.getKey();
                double r = Double.parseDouble(rString.substring(rString.indexOf("_")+1));
                System.out.println("r: " + r);
                BigDecimal bigR = new BigDecimal(r);

                BigDecimal tempW = bigW.divide(bigMaxW, 2, BigDecimal.ROUND_UP);
                BigDecimal tempR = bigR.divide(bigSumR, 2, BigDecimal.ROUND_UP);
                BigDecimal multiply = tempW.multiply(tempR);
                result = result + multiply.doubleValue();
            }
        }
        return result;
    }

    private Map<String, Object> calWarnCal(long dateTime, String entId, String deviceId) throws Throwable {
        //开始时间
        long startTime = dateTime - 6 * 60 * 1000;
        //结束时间
        long endTime = dateTime;
        Map<String, Object> parram = new HashMap<String, Object>();
        parram.put("tableId", entId + "." + "GEOSOUNDREALTIME");
        parram.put("deviceId", "\'" + deviceId + "\'");
        parram.put("startTime", startTime);
        parram.put("endTime", endTime);
        List<Double> hourList = geoSoundDao.queryRealTimeByEmergoaDesc(parram);
        //能量平均值
        double avg = GeosoundAlgorithm.averageDouble(hourList);
        //计算脉冲因子
        double divisor = 10 * GeosoundAlgorithm.averageDouble(hourList.subList(0, hourList.size() / 10));
        double dividend = avg;
        double pulseFactor = EigenvalueAlgorithm.divide(divisor, dividend, 0);
        Map<String, Object> map = new HashMap<String, Object>(2);
        map.put("avg", avg);
        map.put("pulseFactor", pulseFactor);
        return map;
    }

    /**
     * 计算脉冲、累计能量和平均能量
     * @param currentTime
     * @throws Exception
     */
    @Override
    public void computePulseAndEnergy(String currentTime) throws Exception {
        long curTime = DateUtils.fomatDateTime(currentTime).getTime();
        long tenMinute = 10 * 60 * 1000;
        //树
        Map<String, Object> treeMap = new HashMap<String, Object>(1);
        treeMap.put("type", "\'" + "Geosound" + "\'");
        List<Map<String, Object>> tree = removeDuplicateWithOrder(treeDao.queryTreeData(treeMap));
        for (Map<String, Object> treeData : tree) {
            Map<String, Object> params = new HashMap<>();
            String entId = (String) treeData.get("entId");
            String deviceId = (String) treeData.get("deviceId");
            params.put("tableId", entId+"."+"GEOSOUNDREALTIME");
            params.put("curTime", curTime);
            params.put("deviceId", "\'" + deviceId + "\'");
            Map<String, Object> data = geoSoundDao.queryGeosoundOnTime(params);
            if (null == data || data.isEmpty()) {
                continue;
            }

            double energy = (double) data.get("emergoa");

            // 计算当前时间前十分钟内的脉冲、累计能量和平均能量
            long endTime = (long) data.get("datetime");
            long startTime = endTime - tenMinute;
            params.put("startTime", startTime);
            params.put("endTime", endTime);
            params.put("deviceId", "\'" + deviceId +"\'");
            List<Map<String, Object>> datas = geoSoundDao.queryGeosoundBeforeTenMinute(params);
            //int len = datas.size();
            double sumEnergy = 0.0;
            int sumPluse = 0;
            for (Map<String, Object> map : datas) {
                double emergoa = (double) map.get("EMERGOA");
                if (emergoa > 0.0) {
                    sumPluse++;
                    sumEnergy = sumEnergy + emergoa;
                }
            }

            double averageEnergy = 0.0;
            if (sumPluse != 0) {
                BigDecimal bigSumEnergy = new BigDecimal(sumEnergy);
                averageEnergy = bigSumEnergy.divide(new BigDecimal(sumPluse), 2, BigDecimal.ROUND_UP).doubleValue();
            }

            Map<String ,Object> result = new HashMap<>();
            result.put("tableId", entId + "." + "GeosoundPulseAndEnergy");
            result.put("pk", "\'" + endTime + ".:." + deviceId + "\'");
            result.put("entId", "\'" + entId + "\'");
            result.put("datetime", endTime);
            result.put("deviceId", "\'" + deviceId + "\'");
            result.put("energy", energy);
            result.put("totalEnergy", sumEnergy);
            result.put("averageEnergy", averageEnergy);
            result.put("pulse", sumPluse);
            System.out.println("result: " + result);
            geoSoundDao.savePulseAndEnergy(result);
        }
    }


    /**************************************重写地音综合预警******************************************/

    /**
     * 存放地音遗传算法的结果R
     * String: 设备号
     * Double: R值
     */
    private Map<String, Double> deviceidAndR = new HashMap<>();

    /**
     * 存放地音一年之内的最大W值
     * String：设备号
     * Double：maxW值
     */
    private Map<String, Integer> deviceidAndMaxW = new HashMap<>();


    /**
     * 2016-01-01 00:00:00的时间戳:1451577600000
     * 2018-01-01 00:00:00的时间戳:1514736000000
     */
    private final String START_DATETIME = "1514736000000";

    /**
     * 2017-01-01 00:00:00的时间戳:1483200000000
     * 2019-01-01 00:00:00的时间戳:1546272000000
     */
    private final String END_DATETIME = "1546272000000";

    /**
     * 设备号和能量均值特征参
     */
    private Map<String, Double> deviceidAndV1 = new HashMap<>();

    /**
     * 设备号和脉冲因子特征参
     */
    private Map<String, Double> deviceidAndV2 = new HashMap<>();

    /**
     * 设备号和预警持续时间
     */
    private Map<String, Double> deviceidAndTime = new HashMap<>();



    /*public GeosoundImpl() {
        //init(START_DATATIME, END_DATATIME);
    }*/


    public synchronized void init(String startTime, String entTime) {
        // 得到每个设备号的R值
        Map<String, Object> params = new HashMap<>();
        params.put("tableId", "GEOSOUNDWARNINGSTUDY");
        List<Map<String, Object>> studyInfos = geoSoundDao.queryGeosoundWarningStudy(params);
        for (Map<String, Object> map : studyInfos) {
            String entId = (String) map.get("entId");
            String deviceId = (String) map.get("deviceId");
            deviceidAndR.put(deviceId, (Double) map.get("R1"));
            deviceidAndTime.put(deviceId, (Double) map.get("T1"));
            // 能量均值特征参
            Double V1 = (Double) map.get("best2");
            // 脉冲因子特征参
            Double V2 = (Double) map.get("best3");

            deviceidAndV1.put(deviceId, V1);
            deviceidAndV2.put(deviceId, V2);

            // 得到每个设备号的MaxW值
            int maxW = 0;
            Map<String, Integer> datetimeAndW = new HashMap<>();

            params.put("startTime", startTime);
            params.put("endTime", entTime);
            params.put("deviceId", "\'" + deviceId + "\'");
            params.put("tableId", entId + "." + "CALGEOPULSE");
            List<Map<String, Object>> pulseFactors = geoSoundDao.queryPulseFactor(params);

            for (Map<String, Object> pulseFactorMap : pulseFactors) {
                int w = 0;
                String datetime = String.valueOf(pulseFactorMap.get("datetime"));
                Double pulseFactor = (Double) pulseFactorMap.get("pulseFactor");
                if (pulseFactor > V2) {
                    w++;
                    datetimeAndW.put(datetime, w);
                } else {
                    datetimeAndW.put(datetime, w);
                }
            }

            params.put("tableId", entId + "." + "CALGEOEMERGOA");
            List<Map<String, Object>> avgEmergoas = geoSoundDao.queryAvgEmergoa(params);
            for (Map<String, Object> avgEmergoaMap : avgEmergoas) {
                String datetime = String.valueOf(avgEmergoaMap.get("datetime"));
                Double averageEnergy = (Double) avgEmergoaMap.get("avgemergoa");

                Integer w = datetimeAndW.get(datetime);
                if (null == w) {
                    w = 0;
                    if (averageEnergy > V1) {
                        datetimeAndW.put(datetime, 1);
                    } else {
                        datetimeAndW.put(datetime, 0);
                    }
                } else {
                    if (averageEnergy > V1) {
                        w++;
                        datetimeAndW.put(datetime, w);
                    } else {
                        datetimeAndW.put(datetime, w);
                    }
                }
                maxW = maxW > w ? maxW : w;
            }
            deviceidAndMaxW.put(deviceId, maxW);
        }
        System.out.println("deviceidAndMaxW: " + deviceidAndMaxW);
    }


    @Override
    public void warningV2(String currentTime) throws Exception {
        //[t-1min,t]
        String startTime =
                DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", DateUtils.getBeforeMinuteDate(-60, currentTime));
        String endTime = DateUtils.getCurrentMinuteStartTime("yyyy-MM-dd HH:mm:ss", currentTime);

        Map<String, Object> treeMap = new HashMap<String, Object>(1);
        treeMap.put("type", "\'" + "Geosound" + "\'");

        if (deviceidAndMaxW.size() == 0) {
            init(START_DATETIME, END_DATETIME);
        }

        long sTime = DateUtils.fomatDateTime(startTime).getTime();
        long eTime = DateUtils.fomatDateTime(endTime).getTime();

        // 设备号和当前时间的w值
        Map<String, Integer> deviceidAndW = new HashMap<>();

        String entId = "";
        long datetime = 0l;
        // 树
        List<Map<String, Object>> tree = removeDuplicateWithOrder(treeDao.queryTreeData(treeMap));
        for (Map<String, Object> treeData : tree) {
            entId = (String) treeData.get("entId");
            String deviceId = (String) treeData.get("deviceId");


            Map<String, Object> params = new HashMap<>();
            params.put("startTime", sTime);
            params.put("endTime", eTime);
            params.put("deviceId", "\'" + deviceId + "\'");

            // 能量均值
            params.put("tableId", entId + "." + "CALGEOEMERGOA");
            params.put("flag", 1);
            int w = 0;
            List<Map<String, Object>> avlEmergoaList = geoSoundDao.queryAvgEmergoa(params);
            if (avlEmergoaList.size() == 1) {
                Map<String, Object> avlEmergoaMap = avlEmergoaList.get(0);
                datetime = (long) avlEmergoaMap.get("datetime");
                double avlEmergoa = (double) avlEmergoaMap.get("avgemergoa");
                if (avlEmergoa > deviceidAndV1.get(deviceId)) {
                    w++;
                }
            }

            // 脉冲因子
            params.put("tableId", entId + "." + "CALGEOPULSE");
            List<Map<String, Object>> pulseFactorList = geoSoundDao.queryPulseFactor(params);
            if (pulseFactorList.size() == 1) {
                Map<String, Object> pulseFactorMap = pulseFactorList.get(0);
                datetime = (long) pulseFactorMap.get("datetime");
                double pulseFactor = (double) pulseFactorMap.get("pulseFactor");
                if (pulseFactor > deviceidAndV2.get(deviceId)) {
                    w++;
                }
            }

            synchronized (this) { // 加锁，防止线程安全问题
                // 更新设备号中的maxW
                int maxW = deviceidAndMaxW.get(deviceId) > w ? deviceidAndMaxW.get(deviceId) : w;
                deviceidAndMaxW.put(deviceId, maxW);

                // 放入当前设备的w值
                deviceidAndW.put(deviceId, w);

                // 查询这段时间内是否有大能量事件发生，如果有，则需要重新计算预警能力
                params.put("tableId", entId +"." + "GEOSOUNDREALTIME" + "_" + deviceId.replace("-", "_"));
                if (R == 0.0) {
                    params.put("startTime", START_DATETIME);
                    params.put("endTime", END_DATETIME);
                    List<Map<String, Object>> realGeosoundList = geoSoundDao.queryRealGeosound(params);
                    //computeHistoryR(START_DATATIME, END_DATATIME);
                    R = computeR(realGeosoundList, entId);
                } else {
                    List<Map<String, Object>> realGeosoundList = geoSoundDao.queryRealGeosound(params);
                    R = computeR(realGeosoundList, entId);
                    deviceidAndR.put(deviceId, R);
                }
            }
        }

        // 计算预警程度W
        double W = computeW(deviceidAndW);
        System.out.println("综合预警值w: " + W + " R: " + R + " datetime: " + datetime);
        // 预警结果W和预警能力R存入表中
        Map<String, Object> resultMap = new HashMap<String, Object>();
        resultMap.put("tableId", entId + "." + "GEOSOUNDWARNING");
        resultMap.put("entId", "\'" + entId + "\'");
        resultMap.put("pk", "\'" + datetime + "\'");
        resultMap.put("datetime", datetime);
        resultMap.put("w", W);
        resultMap.put("R", R);
        //geoSoundDao.saveWarning(resultMap);
    }


    /**
     * 预警能力R
     */
    private double R = 0.0;

    /**
     * 报对次数
     */
    private int rightWarningNumber = 0;

    /**
     * 应预警总次数
     */
    private int shouldWarningNumber = 0;


    /**
     * 计算历史数据的预警能力R
     * @param startTime
     * @param endTime
     */
    /*private void computeHistoryR(String startTime, String endTime) {

    }*/


    /**
     * 遗传算法计算出来的预警时间
     */
    private double warningTimes = 0.0;



    /**
     * 计算预警能力R
     * @param realGeosoundList
     * @return
     */
    private double computeR(List<Map<String, Object>> realGeosoundList, String entId) {

        if (realGeosoundList == null || realGeosoundList.size() == 0) {
            return R;
        }

        for (int i=0; i<realGeosoundList.size(); i++) {
            double emergoa = (double) realGeosoundList.get(i).get("emergoa");
            long datetime = (long) realGeosoundList.get(i).get("datetime");
            if (emergoa > 100000) {
                // 如果前一天内预警程度达到0.5，报对次数加1
                long preDatetime = datetime - 24 * 60 * 1000;
                Map<String, Object> params = new HashMap<>();
                params.put("startTime", preDatetime);
                params.put("endTime", datetime);
                params.put("tableId", entId + "." + "GEOSOUNDWARNING");
                boolean isWarning = false;
                List<Double> warnings = geoSoundDao.queryGeosoundWarning(params);
                for (int j=0; j<warnings.size(); j++) {
                    if (warnings.get(j) > 0.5) {
                        isWarning = true;
                    }
                }
                if (isWarning) {
                    rightWarningNumber++;
                }
                shouldWarningNumber++;
                // 需要重新计算R,R的计算公式为：R=报对次数/应报警总次数-预警占用时间/预警研究总时间
                // 四舍五入取小数点后两位
                double temp1 = new BigDecimal(rightWarningNumber/shouldWarningNumber, new MathContext(2, RoundingMode.HALF_DOWN)).doubleValue();

                // 预警占用时间=报对次数(预警的次数) * 遗传算法计算出来的预警时长(固定为两天时间，单位为分钟)
                if (0.0 == warningTimes) {
                    warningTimes = rightWarningNumber * (2 * 24 * 60);
                }

                // 预警研究总时间,就是此刻到开始研究的总时间。例如，数据是从2016年开始的，那么预警研究总时间就是此刻到2016年的时间
                BigInteger subtract = BigInteger.valueOf(datetime).subtract(BigInteger.valueOf(Long.parseLong(START_DATETIME)));
                // 四舍五入取小数点后两位
                //double temp2 = new BigDecimal(subtract).divide(new BigDecimal(60000l), 2, BigDecimal.ROUND_HALF_DOWN).doubleValue();
                double temp2 = new BigDecimal(warningTimes).divide(new BigDecimal(subtract), 2, BigDecimal.ROUND_HALF_DOWN).doubleValue();

                R = temp1 - temp2;
            }
        }
        return R;
    }



    /**
     * 求遗传算法计算出来多个设备R的和
     * @return
     */
    private double sumR() {

        double result = 0.0;
        for (Map.Entry<String, Double> entry : deviceidAndR.entrySet()) {
            result = result + entry.getValue();
        }
        return result;
    }

    /**
     * 计算地音多参量综合预警的W值
     * @param deviceidAndW
     * @return
     */
    private double computeW(Map<String, Integer> deviceidAndW) {

        double result = 0.0;
        double sumR = sumR();
        for (Map.Entry<String, Integer> entry : deviceidAndW.entrySet()) {
            String deviceId = entry.getKey();
            int w = entry.getValue();

            int maxW = deviceidAndMaxW.get(deviceId);
            double R = deviceidAndR.get(deviceId);
            if (0 == maxW) {
                result = 0.0;
            } else {
                double tempW = w / maxW;
                BigDecimal tempR = new BigDecimal(R).divide(new BigDecimal(sumR), 2, BigDecimal.ROUND_HALF_DOWN);
                result = result + new BigDecimal(tempW).multiply(tempR, new MathContext(2, RoundingMode.HALF_DOWN)).doubleValue();
            }
        }
        return result;
    }



}
